#pragma once
#include "UtTestBase.h"
#include "ReportBuilder.h"
#include "TestRunnerExchange2.h"
#include "XmlFileFilter.h"
#include "TextReport.h"
#include "XmlReport.h"


class CClientEngine
{
ut_private:
	struct TestGroupItem
	{
		LPMakeInstanceFunc		fMakeInstance;
		LPDestroyInstanceFunc	fDestroyInstance;
		LPGetTestsFunc			fGetTests;
		LPCWSTR					lpName;
	};

	//the global storage of test groups
	//WARNING!!! Do not use directly use GetRegisterTestGroups instead
	static CAtlArray<TestGroupItem>* s_pTestGroups;

	//a local copy of storage used during a test run
	CAtlArray<TestGroupItem> m_aTestGroups;

	CReportBuilder	m_csReportBuilder;
	//an instance of the xml file test filter
	CXmlFileFilter m_csXmlFileFilter;
	//an instance of client server data exchange object
	CTestRunnerExchange2 m_csTestRunnerExchange2;
	//an instance of text reporter, is used to report on the application console
	CTextReport m_csTextReport;
	//an instance of xml reporter
	CXmlReport m_csXmlReport;
	//defines filter that is used to filter and sort a test set
	EFilter	m_eFilter;
	//represent a unit test command line option (read only settings)
	CUtProjCommandLineParser	m_csUtProjCommandLineParser;
	
	//internal accessor to the regdister test group array
	static CAtlArray<TestGroupItem> & GetRegisterTestGroups();
public:
	CClientEngine(void);
	~CClientEngine(void);

	//adds test group
	static int Add(LPMakeInstanceFunc fMakeInstance, LPDestroyInstanceFunc fDestroyInstance, LPGetTestsFunc fGetTests, LPCWSTR lpName);
	//free memory
	static void Free();
	//runs tests
	//void Run();
	//runs tests and makes a report
	void Run2();
ut_private:
	inline EFilter GetFilter() const { return m_eFilter; }

	//Defines if the xml filter has been successfully loaded from the application command line
	inline BOOL IsXmlFilterLoaded() const { return m_csXmlFileFilter.IsLoaded(); }

	//Define if the running application under debugging and a visual studio is ready to receive reports
	inline BOOL IsServerConnected() const { return m_csTestRunnerExchange2.IsConnected(); }

	static ERunStatus MakeRunStatus(const CUtException & rEx);
	
	//wraps create execution of the given unit test group in __try __except
	BOOL CreateTestGroupSehWrapper(LPMakeInstanceFunc func, void* & pTestGroup, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();
	//wraps create execution of the given unit group cpp try catch
	BOOL CreateTestGroupCppWrapper(LPMakeInstanceFunc func, void* & pTestGroup, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();

	//wraps delete execution of the given unit test group in __try __except
	void DeleteTestGroupSehWrapper(LPDestroyInstanceFunc func, void* pTestGroup, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();
	//wraps delete execution of the given unit group cpp try catch
	void DeleteTestGroupCppWrapper(LPDestroyInstanceFunc func, void* pTestGroup, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();

	//wraps execution of the given unit test in __try __except
	void RunTestSehWrapper(void* pTestGroup, LPTestFunc func, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();
	//wraps execution of the given unit test cpp try catch
	void RunTestCppWrapper(void* pTestGroup, LPTestFunc func, ERunStatus & rRunStatus, CAtlStringW & wstrReport, CUtException::EActionCode & rActionCode) throw();

	struct SortedRunGroupItem
	{
		LPMakeInstanceFunc		fMakeInstance;
		LPDestroyInstanceFunc	fDestroyInstance;
		LPCWSTR					lpName;
		CRBMultiMap<DWORD, const UtTestEntry*> mapUtTestEntries;

		SortedRunGroupItem() {};
		SortedRunGroupItem(const SortedRunGroupItem & r);
	};

	BOOL PrepareTestSet(CRBMultiMap<DWORD, SortedRunGroupItem> & rSortedRunGroups);
	BOOL DefineTestsToRun(TestPackTransData & rTestPackTransData);
	BOOL SortTestGroupByLParam(const TestPackTransData & rTestPackTransData, CRBMultiMap<DWORD, SortedRunGroupItem> & mapSortedRunGroups);
};
